﻿// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using Microsoft.AspNetCore.Components;

namespace BootstrapBlazor.Components;

/// <summary>
/// <see cref="Navbar"/> 组件是一个包装器，它将logo、导航和其他元素封装到简洁的菜单或侧栏中。
/// </summary>
public sealed partial class Navbar
{
    /// <summary>
    /// 获得 样式集合
    /// </summary>
    /// <returns></returns>
    public string? ClassString => CssBuilder.Default("navbar")
        .AddClass("navbar-initial", !Initialized)
        .AddClass("navbar-rtl", Initialized && IsRTL)
        .AddClass(ModeStyle, Initialized)
        .AddClass(ThemeStyle, Initialized)
        .AddClass(BreakPointStyle, Initialized)
        .AddClassFromAttributes(AdditionalAttributes)
        .Build();

    /// <summary>
    /// 获得 样式集合
    /// </summary>
    /// <returns></returns>
    private string? StyleClassString => CssBuilder.Default()
        .AddClass($"--navbar-v-width:{VerticalWidth}px;", VerticalWidth > 230)
        .AddClass($"--navbar-v-zindex:{VerticalZindex};", VerticalZindex > 0)
        .AddClass($"--navbar-v-popout-menu-width:{VerticalMenuWidth}px;", VerticalMenuWidth > 180)
        .AddStyleFromAttributes(AdditionalAttributes)
        .Build();

    /// <summary>
    /// 获得 样式集合
    /// </summary>
    /// <returns></returns>
    public string? ToggleClassString => CssBuilder.Default("fa fa-fw")
        .AddClass("fa-angle-left", Visible)
        .AddClass("fa-angle-right", !Visible)
        .Build();

    /// <summary>
    /// 组件的状态
    /// </summary>
    private NavbarState _state = new();

    /// <summary>
    /// 控制当前的状态。
    /// </summary>
    [Parameter]
    public bool Visible
    {
        get => _state.Visible;
        set
        {
            if (_state.Visible != value)
            {
                _state = _state with { Visible = value };
                VisibleChanged.InvokeAsync(value);
            }
        }
    }

    /// <summary>
    /// 获得/设置 导航栏可见性变化时回调。
    /// </summary>
    [Parameter]
    public EventCallback<bool> VisibleChanged { get; set; }

    /// <summary>
    /// 获得/设置 显示方向，默认水平显示。
    /// </summary>
    [Parameter]
    public NavbarMode Mode
    {
        get => _state.Mode;
        set
        {
            if (_state.Mode != value)
            {
                _state = _state with { Mode = value };
            }
        }
    }

    /// <summary>
    /// 获得/设置 当前 <see cref="Navbar"/> 组件折叠模式，默认隐藏。
    /// </summary>
    [Parameter]
    public NavbarCollapseMode CollapseMode
    {
        get => _state.CollapseMode;
        init => _state = _state with { CollapseMode = value };
    }

    /// <summary>
    /// 获得/设置 当前 <see cref="Navbar"/> 组件的主题，默认亮色调
    /// </summary>
    [Parameter]
    public NavbarTheme Theme
    {
        get => _state.Theme;
        init => _state = _state with { Theme = value };
    }

    /// <summary>
    /// 获得/设置 当前 <see cref="Navbar"/> 组件垂直显示时的层级，默认1110
    /// </summary>
    [Parameter]
    public int? VerticalZindex { get; init; }

    /// <summary>
    /// 获得/设置 当前 <see cref="Navbar"/> 组件垂直显示时的宽度，最小230px
    /// </summary>
    [Parameter]
    public int? VerticalWidth { get; init; }

    /// <summary>
    /// 获得/设置 当前 <see cref="Navbar"/> 组件垂直显示时，内置菜单的宽度，最小180px
    /// </summary>
    [Parameter]
    public int? VerticalMenuWidth { get; init; }

    /// <summary>
    /// 获得/设置 折叠显示的临界断点，默认小屏幕 576px，仅在水平菜单中生效
    /// </summary>
    [Parameter]
    public BreakPoint BrokenPoint
    {
        get => _state.BrokenPoint;
        init => _state = _state with { BrokenPoint = value };
    }

    /// <summary>
    /// 获得/设置 是否负布局
    /// </summary>
    [Parameter]
    public bool IsRTL
    {
        get => _state.IsRTL;
        set => _state = _state with { IsRTL = value };
    }

    /// <summary>
    /// 获得/设置 子组件内容
    /// </summary>
    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    /// <summary>
    /// 获得/设置 是否第一次渲染完成
    /// </summary>
    private bool Initialized { get; set; }

    /// <summary>
    /// 获得 当前主题样式
    /// </summary>
    private string? ModeStyle => $"navbar-{Mode.ToDescriptionString()}";

    /// <summary>
    /// 获得 当前主题样式
    /// </summary>
    private string? ThemeStyle => Theme switch
    {
        NavbarTheme.None => null,
        _ => $"navbar-{Theme.ToDescriptionString()}",
    };

    /// <summary>
    /// 获得 当前断点对应的显示样式
    /// </summary>
    private string? BreakPointStyle
    {
        get
        {
            //非水平菜单从不折叠
            if (!_state.IsHorizontal)
            {
                return "navbar-expand";
            }

            return _state.BrokenPoint switch
            {
                BreakPoint.ExtraExtraLarge => "navbar-expand-xl",
                BreakPoint.ExtraLarge => "navbar-expand-xl",
                BreakPoint.Large => "navbar-expand-lg",
                BreakPoint.Medium => "navbar-expand-md",
                BreakPoint.Small => "navbar-expand-sm",
                BreakPoint.ExtraSmall => "navbar-expand-xs",
                _ => "navbar-expand",
            };
        }
    }

    /// <summary>
    /// 获得 当前 <see cref="Navbar"/> 组件是否超出临界断点
    /// </summary>
    private string IsBrokenString => _state.IsBroken ? "true" : "false";

    /// <summary>
    /// 获得 当前折叠模式
    /// </summary>
    private string? CollapseModeString => Visible ? null : CollapseMode.ToDescriptionString();

    /// <summary>
    /// OnInitialized
    /// </summary>
    protected override void OnInitialized()
    {
        base.OnInitialized();

        _state = _state with { Id = Id };
    }

    /// <summary>
    /// OnAfterRender
    /// </summary>
    /// <param name="firstRender"></param>
    protected override async void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);

        if (firstRender)
        {
            Initialized = true;
            _state.CurrentPoint = await JSRuntime.InvokeAsync<BreakPoint>(func: "bb_get_responsive");
            await InvokeAsync(StateHasChanged);
        }
    }

    /// <summary>
    /// 断点变化通知
    /// </summary>
    /// <param name="breakPoint"></param>
    /// <returns></returns>
    private async Task OnBreakPointChanged(BreakPoint breakPoint)
    {
        if (_state.CurrentPoint != breakPoint)
        {
            _state.CurrentPoint = breakPoint;
            if (_state.IsHorizontal && _state.IsBroken)
            {
                await InvokeAsync(StateHasChanged);
            }
        }
    }

    /// <summary>
    /// 切换组件状态
    /// </summary>
    internal Task Toggle()
    {
        Visible = !Visible;
        return InvokeAsync(StateHasChanged);
    }
}
